#include "ECS/XML/XmlSerializer.h"
#include <string>
#include "ECS/Patterns/Nullable.h"

namespace ECS
{
	class ClassXmlParser : public IXmlParser
	{
	public:
		virtual void parseElement(MetaVariable* v, void* instance, TiXmlElement* element) override
		{
		}
	};

	class IntXmlParser : public IXmlParser
	{
	public:
		virtual void parseAttribute(MetaVariable* v, void* instance, const char* attrValue)
		{
			int r = std::stoi(attrValue);
			v->setValue(instance, &r);
		}
	};
	class NIntXmlParser : public IXmlParser
	{
	public:
		virtual void parseAttribute(MetaVariable* v, void* instance, const char* attrValue)
		{
			ECS::Nullable<int> r;
			if (attrValue != nullptr)
				r = std::stoi(attrValue);
			v->setValue(instance, &r);
		}
	};
	class FloatXmlParser : public IXmlParser
	{
	public:
		virtual void parseAttribute(MetaVariable* v, void* instance, const char* attrValue)
		{
			float r = std::stof(attrValue);
			v->setValue(instance, &r);
		}
	};
	class NFloatXmlParser : public IXmlParser
	{
	public:
		virtual void parseAttribute(MetaVariable* v, void* instance, const char* attrValue)
		{
			ECS::Nullable<float> r;
			if (attrValue)
				r = std::stof(attrValue);
			v->setValue(instance, &r);
		}
	};
	class StringXmlParser : public IXmlParser
	{
	public:
		virtual void parseAttribute(MetaVariable* v, void* instance, const char* attrValue)
		{
			std::string r = attrValue;
			v->setValue(instance, &r);
		}
	};

	XMLSerializer::XMLSerializer()
	{
		_parsers[getTypeID<int>()] = new IntXmlParser();
		_parsers[getTypeID<ECS::Nullable<int> >()] = new NIntXmlParser();
		_parsers[getTypeID<float>()] = new FloatXmlParser();
		_parsers[getTypeID<ECS::Nullable<float> > ()] = new NFloatXmlParser();
		_parsers[getTypeID<std::string>()] = new StringXmlParser();
	}

	void* XMLSerializer::readFromXml(TiXmlElement* element, MetaClass* cls)
	{
		auto ctr = cls->getConstructor();
		if (!ctr)
			return nullptr;

		void* def = ctr->call();

		while (cls != nullptr)
		{
			for(size_t i = 0; i < cls->variables.size(); ++i)
			{
				MetaVariable* v = cls->variables[i];

				auto parser = _parsers[v->typeID];
				if (parser != nullptr)
				{
					const char* attr = element->Attribute(v->name);
					if (attr != nullptr)
						parser->parseAttribute(v, def, attr);
				}

			}

			cls = cls->base;
		}

		return def;
	}

	void XMLSerializer::writeToXml( TiXmlElement* element, MetaClass* cls, void* instance )
	{

	}

}